package com.jxtc.enterprise.hr.service;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jxtc.enterprise.common.constants.MealTypeEnum;
import com.jxtc.enterprise.common.mapper.OrderDetailMapper;
import com.jxtc.enterprise.common.mapper.OrderMapper;
import com.jxtc.enterprise.common.vo.PaginationResponseVO;
import com.jxtc.enterprise.hr.dto.OrderDetailDTO;
import com.jxtc.enterprise.hr.dto.OrderDetailStoreFoodDTO;
import com.jxtc.enterprise.hr.dto.OrderExportDTO;
import com.jxtc.enterprise.hr.dto.OrderStatisticDTO;
import com.jxtc.enterprise.hr.vo.HrOrderDetailVO;
import com.jxtc.enterprise.hr.vo.HrOrderVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Sheet;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class HrOrderManagementService {

    private final OrderMapper orderMapper;
    private final OrderDetailMapper orderDetailMapper;

    /**
     * 根据公司 ID 和时间范围分页查询订单数据
     *
     * @param companyId 公司 ID
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param current   当前页
     * @param size      每页展示数据量
     * @return 分页数据
     */
    public PaginationResponseVO<HrOrderVO> pageOrderByCompanyIdAndTime(String companyId, String startTime, String endTime, int current, int size) {
        Page<OrderStatisticDTO> page = new Page<>(current, size);

        // 如果开始时间为空，则设置为最早日期
        if (startTime == null || startTime.isEmpty()) {
            startTime = "2024-01-01";
        }
        LocalDate startDate = LocalDateTimeUtil.parseDate(startTime);

        // 如果结束时间为空，则设置为当前日期的后一天；如果结束时间不为空，则将 yyyy-MM-dd 格式的时间转换成 LocalDate 类型
        LocalDate today = LocalDate.now();
        LocalDate endDate = today.plusDays(1);
        if (endTime != null && !endTime.isEmpty()) {
            endDate = LocalDateTimeUtil.parseDate(endTime);
        }
        // 结束日期增加 1 天，防止当天数据查询不到
        // LocalDate endDate = rowEndDate.plusDays(1);

        Page<OrderStatisticDTO> result = orderMapper.queryOrderStatistic(page, companyId, startDate, endDate);
        List<HrOrderVO> records = result.getRecords().stream().map(HrOrderVO::new).collect(Collectors.toList());

        return new PaginationResponseVO<>(result.getTotal(), result.getCurrent(), records);
    }

    /**
     * 根据公司 ID 和日期查询当日具体的订单详情
     *
     * @param companyId 公司 ID
     * @param date      日期，如 2024-05-31
     * @return 分页后的订单详情
     */
    public PaginationResponseVO<HrOrderDetailVO> pageOrderDetailByCompanyIdAndDate(String companyId, String date, int current, int size) {
        Page<OrderDetailDTO> page = new Page<>(current, size);
        LocalDate localDate = LocalDateTimeUtil.parseDate(date);
        Page<OrderDetailDTO> result = orderMapper.queryOrderDetail(page, companyId, localDate);

        // 订单名称规则：将一份订单中可能存在的多个餐品名称使用 ", " 拼接
        List<HrOrderDetailVO> records = result.getRecords().stream().map(detail -> {
            HrOrderDetailVO vo = new HrOrderDetailVO(detail);
            String orderId = detail.getOrderId();
            List<OrderDetailStoreFoodDTO> foodDetailList = orderDetailMapper.selectByOrderId(orderId);
            String orderName = foodDetailList.stream().map(OrderDetailStoreFoodDTO::getFoodName).collect(Collectors.joining(","));
            if (!foodDetailList.isEmpty()) {
                String mealTypeCn = getMealTypeChineseNameFromEnum(foodDetailList.get(0).getMealType());
                vo.setMealType(mealTypeCn);
            }
            vo.setOrderName(orderName);
            return vo;
        }).collect(Collectors.toList());
        return new PaginationResponseVO<>(result.getTotal(), result.getCurrent(), records);
    }

    /**
     * 将数据库中保存的用餐时段的英文名称转换成对应的中文名称
     *
     * @param mealTypeEn 用餐时段的英文名称
     * @return 中文名称
     */
    private String getMealTypeChineseNameFromEnum(String mealTypeEn) {
        return Arrays.stream(MealTypeEnum.values())
                .filter(mealTypeEnum -> mealTypeEnum.getMealTypeEn().equals(mealTypeEn))
                .map(MealTypeEnum::getMealTypeCn)
                .findAny()
                .orElse("");
    }


    public void export2Excel(HttpServletResponse response, OrderExportDTO dto) {

        List<String> dateList = dto.getDateList();

        if (dto.getSelectAll() != null && dto.getSelectAll()) {
            PaginationResponseVO<HrOrderVO> vo = pageOrderByCompanyIdAndTime(dto.getCompanyId(), null, null, 1, Integer.MAX_VALUE);
            dateList = vo.getRecords().stream().map(HrOrderVO::getDate).collect(Collectors.toList());
        }

        try (ExcelWriter writer = ExcelUtil.getWriter(true)) {
            boolean firstSheet = true;
            List<HrOrderDetailVO> summaryOrderDetailList = new ArrayList<>();
            for (String date : dateList) {
                PaginationResponseVO<HrOrderDetailVO> orderDetailVO = pageOrderDetailByCompanyIdAndDate(dto.getCompanyId(), date, 1, Integer.MAX_VALUE);
                List<Map<String, Object>> data = new ArrayList<>();
                summaryOrderDetailList.addAll(orderDetailVO.getRecords());

                int idx = 1;
                for (HrOrderDetailVO orderDetail : orderDetailVO.getRecords()) {
                    data.add(createRow(idx++, orderDetail.getUsername(), orderDetail.getDepartment(), orderDetail.getOrderName(), orderDetail.getPrice(), orderDetail.getOrderTime()));
                }
                addSheet(writer, date, data, firstSheet);
                firstSheet = false;
            }
            // 将所有 sheet 页的数据汇总到一个 sheet 页中，并按下单时间降序排列
            addSummarySheet(summaryOrderDetailList, writer);

            String filename = System.currentTimeMillis() + ".xlsx";

            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + filename);
            writer.flush(response.getOutputStream(), true);
        } catch (Exception e) {
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            throw new RuntimeException("Error while generating Excel file", e);
        }
    }

    private void addSummarySheet(List<HrOrderDetailVO> summaryOrderDetailList, ExcelWriter writer) {
        List<HrOrderDetailVO> sortedByTime = summaryOrderDetailList.stream()
                .sorted(Comparator.comparing(HrOrderDetailVO::getOrderTime, Comparator.reverseOrder()))
                .collect(Collectors.toList());

        List<Map<String, Object>> data = new ArrayList<>();
        int idx = 1;
        for (HrOrderDetailVO orderDetail : sortedByTime) {
            data.add(createRow(idx++, orderDetail.getUsername(), orderDetail.getDepartment(), orderDetail.getOrderName(), orderDetail.getPrice(), orderDetail.getOrderTime()));
        }
        // 添加一个新的 sheet 页，并设置为第一个 sheet 页
        Sheet summarySheet = writer.getWorkbook().createSheet("汇总");
        writer.getWorkbook().setSheetOrder("汇总", 0);

        // 设置“餐品”这一列的宽度，索引从 0 开始
        int dishNameColumnIndex = 3;
        summarySheet.setColumnWidth(dishNameColumnIndex, 40 * 256);

        // 设置“下单时间”这一列的宽度
        int orderTimeColumnIndex = 5;
        summarySheet.setColumnWidth(orderTimeColumnIndex, 20 * 256);

        // 写入数据
        writer.setSheet("汇总");
        writer.write(data, true);

        // 默认打开 “汇总” 这个 sheet 页
        writer.getWorkbook().setActiveSheet(0);
    }

    private void addSheet(ExcelWriter writer, String sheetName, List<Map<String, Object>> data, boolean firstSheet) {
        if (firstSheet) {
            writer.renameSheet(sheetName);
        } else {
            writer.setSheet(sheetName);
        }
        writer.write(data, true);

        // 获取当前工作表
        Sheet sheet = writer.getSheet();

        // 设置“餐品”这一列的宽度，索引从 0 开始
        int dishNameColumnIndex = 3;
        sheet.setColumnWidth(dishNameColumnIndex, 40 * 256);

        // 设置“下单时间”这一列的宽度
        int orderTimeColumnIndex = 5;
        sheet.setColumnWidth(orderTimeColumnIndex, 20 * 256);
    }

    private Map<String, Object> createRow(Integer index, String username, String department, String dish, Double price, String orderTime) {
        // 使用 LinkedHashMap 而不是 HashMap 防止标题栏乱序
        Map<String, Object> row = new LinkedHashMap<>();
        row.put("序号", index);
        row.put("用户名", username);
        row.put("部门", department);
        row.put("餐品", dish);
        row.put("价格", price);
        row.put("下单时间", orderTime);
        return row;
    }
}
